package cn.yl.game.dice.controller;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;

import cn.yl.game.dice.domain.User;

@Component
@ServerEndpoint("/dice/{msg}")
public class DiceSocket {
	
	private static ConcurrentHashMap<String, List<Session>> rooms = new ConcurrentHashMap<>();
	private static ConcurrentHashMap<String, String> roomOwner = new ConcurrentHashMap<>();
	private static ConcurrentHashMap<String, List<User>> usersInRoom = new ConcurrentHashMap<String, List<User>>();
	private Random random = new Random();
	
	private Session currentSession;
	
	private synchronized void addRooms(String room,Session session) {
		List<Session> sessions = rooms.get(room);
		if(sessions == null) {
			sessions = new ArrayList<Session>();
		}
		sessions.add(session);
		rooms.put(room, sessions);
	}
	
	
	private synchronized void addUsers(String room,User user) {
		List<User> list = usersInRoom.get(room);
		if(list == null) {
			list = new ArrayList<>();
			list.add(user);
		}else {
			Iterator<User> it = list.iterator();
			while(it.hasNext()) {
				User u = it.next();
				if(u.getSession().getId().equals(user.getSession().getId()) && u.getUserName().equals(user.getUserName()) || !user.getSession().isOpen()) {
					it.remove();
					break;
				}
			}
			list.add(user);
		}
		usersInRoom.put(room, list);
	}
	
	private synchronized void deleteSession(Session session) {
		for(Entry<String,List<User>> e : usersInRoom.entrySet()) {
			List<User> list = e.getValue();
			Iterator<User> users = list.iterator();
			while(users.hasNext()) {
				User u = users.next();
				System.out.println("---:"+u.getSession().isOpen());
				if(u.getSession().getId().equals(session.getId()) || !u.getSession().isOpen()) {
					users.remove();
					break;
				}
			}
		}
		
		for(Entry<String,List<Session>> e : rooms.entrySet()) {
			List<Session> list = e.getValue();
			Iterator<Session> sessions = list.iterator();
			while(sessions.hasNext()) {
				if(sessions.next().equals(session) ) {
					sessions.remove();
					break;
				}
			}
		}
	}
	
	@OnOpen
	public void onOpen(@PathParam(value = "msg")String msg,Session session) {
		sendMessage("type=success&", session);
	}
	
	@OnClose
	public void onClose(Session session) {
		//System.out.println(session.getId() + "closed");
		Session s = session;
		deleteSession(s);
	}
	
	@OnError
	public void onError(Session session, Throwable error) {
		error.printStackTrace();
	}
	
	@OnMessage
	public void onMessage(String msg, Session session) {
		String[] msgs = msg.split("&");
		String username = msgs[0];
		String room = msgs[1];
		String type = msgs[2];
		if("changeAllDot".equals(type)) {
			changeAllDot(room);
			String message = username + "重摇了本房间所有玩家的骰子";
			sendMessageByRoom("type=txt&content="+message, room);
			List<User> users = usersInRoom.get(room);
			String ret = "type=next&";
			for(User u : users) {
				ret += u.getUserName() + ";";
				for(int i : u.getDots()) {
					ret = ret + i + ";";
				}
				ret += "@";
			}
			sendMessageByRoom(ret,room);
		}else if ("changeDot".equals(type)) {
			HashMap<String,Object> last = changeDot(room, username,session);
			int[] dots = (int[]) last.get("lastDots");
			String dotsMsg = "";
			for(int i : dots) {
				dotsMsg += i + "  ,";
			}
			sendMessageByRoom("type=txt&content="+last.get("userName") + "刚刚重摇了,之前的点数为:" + dotsMsg,room);
		}else if("inRoom".equals(type)) {
			inRoom(room, username,session);
			sendMessageByRoom("type=txt&content="+username + " 进入了房间", room);
		}else if("openAllDots".equals(type)) {
			openAllDots(room, username);
			sendMessageByRoom("type=txt&content="+username+"开了,现在可以查看所有玩家的点数了", room);
		}else if("next".equals(type)) {
			List<User> users = usersInRoom.get(room);
			String ret = "type=next&";
			for(User u : users) {
				ret += u.getUserName() + ";";
				for(int i : u.getDots()) {
					ret = ret + i + ";";
				}
				ret += "@";
			}
			sendMessageByRoom(ret,room);
		}
	}
	
	private void sendMessage(String msg, Session session) {
		try {
			session.getBasicRemote().sendText(msg);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void sendMessageByRoom(String msg,String room) {
		List<Session> sessions = rooms.get(room);
		for(Session s : sessions) {
			try {
				if(s.isOpen()) {
					s.getBasicRemote().sendText(msg);
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	//type = openAllDots
	private void openAllDots(String room,String username) {
		List<User> users = usersInRoom.get(room);
		String ret = "type=openAllDots&";
		for(User u : users) {
			ret += u.getUserName() + ";";
			for(int i : u.getDots()) {
				ret = ret + i + ";";
			}
			ret += "@";
		}
		sendMessageByRoom(ret, room);
	}
	
	//type = changeAllDot
	private void changeAllDot(String room) {
		List<User> users = usersInRoom.get(room);
		List<User> newList = new ArrayList<>();
		users.stream().forEach(u -> {
			int[] curDot = generateDot();
			u.setDots(curDot);
			newList.add(u);
			String msg = "type=changeDot&user="+u.getUserName()+"&content=";
			for(int i : curDot) {
				msg += i+";";
			}
			sendMessage(msg,u.getSession());
		});
		usersInRoom.put(room, newList);
	}
	
	//type = changeDot
	private HashMap<String,Object> changeDot(String room,String username,Session session) {
		List<User> users = usersInRoom.get(room);
		HashMap<String, Object> lastDots = new HashMap<>();
		User curUser = null;
		for(User u : users) {
			if(username.equals(u.getUserName())) {
				curUser = u;
				break;
			}
		}
		if(curUser != null) {
			lastDots.put("lastDots", curUser.getDots());
			lastDots.put("userName", curUser.getUserName());
			int[] curDot = generateDot();
			curUser.setDots(curDot);
			addUsers(room, curUser);
			String msg = "type=changeDot&user="+username+"&content=";
			for(int i : curDot) {
				msg += i+";";
			}
			sendMessage(msg,session);
		}
		return lastDots;
	}
	
	//type = inRoom
	private void inRoom(String room,String username,Session session) {
		boolean existRoom = rooms.containsKey(room);
		if(!existRoom) {
			roomOwner.put(room, username);
		}
		addRooms(room, session);
		User user = new User();
		user.setRoomId(room);
		user.setUserName(username);
		int[] dots = generateDot();
		user.setDots(dots);
		user.setSession(session);
		addUsers(room,user);
		List<User> users = usersInRoom.get(room);
		String ret = "type=users&";
		for(User u : users) {
			ret += u.getUserName() + ";";
			for(int i : u.getDots()) {
				ret = ret + i + ";";
			}
			ret += "@";
		}
		String omsg = "type=isOwner&"+roomOwner.get(room) + '&';
		for(int i : dots) {
			omsg += i +";";
		}
		sendMessage(omsg,session);
		sendMessageByRoom(ret, room);
	}
	
	
	private int[] generateDot(){
		return random.ints(1,7).limit(5).toArray();
	}
	
	private int[] initDot() {
		int[] dots = new int[5];
		dots[0] = -1;
		dots[1] = -1;
		dots[2] = -1;
		dots[3] = -1;
		dots[4] = -1;
		return dots;
	}
}
